From: Daniel Boles Date: Thu, 18 Jan 2018 00:51:24 +0000 (+0000) Subject: Widget: Don’t call reset() on NULL EventController X-Git-Tag: archive/raspbian/3.24.39-1+rpi1~1^2~65^2~38^2~46 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=b8e2430486ae3dac4f0c0441608f2d1b032ac794;p=gtk%2B3.0.git Widget: Don’t call reset() on NULL EventController GtkGesture is a GtkEventController. gtk_event_controller_dispose() calls _gtk_widget_remove_controller(). That NULLs the pointer-to-Controller in our EventControllerData but does not delete said ECData from our GList. Subsequently, if that same Widget gets unparent()ed, that method calls unset_state_flags(), which leads to doing reset_controllers() if we are insensitive. Now, unlike most most other loops over the GList of ECData, reset_controllers() does not skip nodes whose pointer-to-Controller is NULL. So, we call gtk_event_controller_reset(NULL) and get a CRITICAL. This surfaced in a gtkmm program. The Gesture is destroyed before the Widget. The Widget then gets dispose()d, which calls unparent()… boom. I didn’t find an MCVE yet but would hope this logic is correct anyway: The simplest fix is to make the loop in gtk_widget_reset_controllers() skip GList nodes with a NULL Controller pointer, like most other such loops, so we avoid passing the NULL to gtk_event_controller_reset(). In other, live cases, _gtk_widget_run_controllers() loops over the GList and removes/frees nodes having NULL Controllers, so that should suffice. But this clearly was not getting a chance to happen in the failing case. https://bugzilla.gnome.org/show_bug.cgi?id=792624 --- diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index e920161026..35ad5b2159 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -17483,6 +17483,10 @@ gtk_widget_reset_controllers (GtkWidget *widget) for (l = priv->event_controllers; l; l = l->next) { controller_data = l->data; + + if (controller_data->controller == NULL) + continue; + gtk_event_controller_reset (controller_data->controller); } }